import { type ShallowRef, ref, shallowRef } from 'vue'
import { loadAsyncComponent } from '../common'
import type { ComponentSchema } from '../../core'

export interface ActivitybarModel {
  id: string
  title: string
  icon: string
  component: any
  visible?: boolean
}

export interface RightSidebarModel {
  id: string
  title: string
  component: any
  visible?: boolean
}

export interface ViewsContainersModel {
  activitybars: ShallowRef<ActivitybarModel[]>
  rightSidebars: ShallowRef<RightSidebarModel[]>
}

export type Components = Record<string, any>

export interface EventModel {
  type: string
  describe: string
}

export interface ActionModel extends EventModel {
  argsConfigs?: ComponentSchema[]
  args?: any[]
}

export interface EditConstraintsModel {
  // 当前组件是否固定不可拖动，可选
  immovable?: boolean
  // 子节点是否固定不可拖动,只控制下一级，可选
  childImmovable?: boolean
  // 表单字段是否固定 不添加随机UUID
  fixedField?: boolean
}

export interface ComponentConfigModel {
  // 组件
  component: any
  // 分组名称（组件分组），不设置分组时仅注册，但不会显示在组件列表中，可选
  groupName?: string
  // 组件图标
  icon?: string
  // 默认组件结构数据
  defaultSchema: ComponentSchema
  // 设计编辑约束
  editConstraints?: EditConstraintsModel
  // 配置
  config: {
    // 属性编辑列表
    attribute?: ComponentSchema[]
    // 样式编辑组件列表
    style?: ComponentSchema[]
    // 可触发事件
    event?: EventModel[]
    // 可执行函数
    action?: ActionModel[]
  }
  // 输入表单组件v-model绑定变量名称 默认 modelValue
  bindModel?: string
  // 用于组件排序，可选 默认值1000, 值越小，组件越靠前
  sort?: number
}

export type ComponentConfigModelRecords = Record<string, ComponentConfigModel>

export interface PublicMethodModel {
  describe?: string
  methodName?: string
  name: string
  method?: (...args: any) => any
  handler: (...args: any) => any
}

export type PublicMethodsModel = Record<string, PublicMethodModel>

export interface ComponentGroup {
  list: ComponentSchema[]
  title: string
}

export type ComponentSchemaGroups = ComponentGroup[]

// 插件管理器类
export class PluginManager {
  // 已初始化基础UI
  initialized = ref(false)

  // 组件对象字典，key 为组件type，value 为组件
  components: Components = {}

  // 组件配置记录字典，key 为组件type，value 为组件配置
  componentConfigs: ComponentConfigModelRecords = {}

  // 基础组件type，切换ui时，可先移除该数组记录的type
  baseComponentTypes: string[] = []

  // 组件模式分组，使用 Vue Composition API 的 ref 进行响应式处理
  componentSchemaGroups = ref<ComponentSchemaGroups>([])

  // 隐藏的组件列表，存储需要隐藏的组件名称
  hiddenComponents: string[] = []

  // 表单模式默认schema数据
  formSchemas: ComponentSchema[] = [
    {
      label: '表单',
      type: 'form',
      componentProps: {
        layout: 'horizontal',
        name: 'default',
        labelWidth: 100,
        labelLayout: 'fixed',
        labelCol: {
          span: 5,
        },
        wrapperCol: {
          span: 19,
        },
        colon: true,
        labelAlign: 'right',
        labelPlacement: 'left',
      },
      children: [],
      id: 'root',
    },
  ]

  // 组件分组名称映射，key 为组件原名称，value 为组件分组映射名称
  componentGroupNameMap: Record<string, string> = {}

  // 组件分组排序列表(设置之后，按该数组下标排序)
  sortedGroups: string[] = ['表单', '布局']

  // 视图容器模型，包含活动栏和右侧边栏的配置
  viewsContainers: ViewsContainersModel = {
    activitybars: shallowRef([]), // 活动栏配置列表
    rightSidebars: shallowRef([]), // 右侧边栏配置列表
  }

  // 公共方法模型，存储插件的公共方法
  publicMethods: PublicMethodsModel = {
    // 示例数据
    // publicTest: {
    //   describe: "测试函数",
    //   name: "test",
    //   handler: (e) => {
    //     console.log(e)
    //     // alert("测试函数弹出");
    //   },
    // },
  }

  /**
   * 添加组件到插件管理器中
   * @param componentType 组件类型
   * @param component 组件
   */
  component(componentType: string, component: any): void {
    if (typeof component === 'function') {
      component = loadAsyncComponent(component)
    }
    // 注册组件
    this.components[componentType] = component
  }

  /**
   * 注册组件到插件管理器中
   * @param componentConfig 组件配置
   */
  registerComponent(componentConfig: ComponentConfigModel): void {
    // 添加组件
    this.component(
      componentConfig.defaultSchema.type,
      componentConfig.component,
    )

    // 输入组件增加动作配置
    if (componentConfig.defaultSchema.input) {
      if (!componentConfig.config.action) {
        componentConfig.config.action = []
      }

      // 补充组件可用方法
      componentConfig.config.action.unshift(
        ...[
          {
            type: 'setValue',
            describe: '设置值',
            // 参数配置
            argsConfigs: [
              {
                ...componentConfig.defaultSchema,
                label: '设置数据',
                field: '0',
              },
            ],
          },
          {
            type: 'getValue',
            describe: '获取值',
          },
        ],
      )
    }

    // 添加组件配置
    this.componentConfigs[componentConfig.defaultSchema.type] = componentConfig

    this.computedComponentSchemaGroups()
  }

  /**
   * 从已记录的基础组件类型中移除特定类型的组件
   * @param componentType 要移除的组件类型
   */
  removeComponent(componentType: string) {
    // 在数组中查找要移除的组件类型的索引
    delete this.componentConfigs[componentType]
    delete this.components[componentType]
  }

  /*
   * 记录基础组件类型
   * @returns baseComponentTypes string[]
   */
  setBaseComponentTypes(baseComponentTypes: string[]) {
    this.baseComponentTypes = baseComponentTypes
  }

  /*
   * 添加基础组件类型
   * @returns baseComponentType string
   */
  addBaseComponentTypes(baseComponentType: string) {
    this.baseComponentTypes.push(baseComponentType)
  }

  /**
   * 移除已记录的基础组件类型
   */
  removeBaseComponents() {
    this.baseComponentTypes.forEach((componentType) => {
      this.removeComponent(componentType)
    })
    this.setBaseComponentTypes([])

    this.computedComponentSchemaGroups()
  }

  /**
   * 获取所有插件管理中的所有组件
   * @returns components
   */
  getComponents(): Components {
    return this.components
  }

  /**
   * 通过type 查询相应的组件
   * @returns components
   */
  getComponent(type: string): any {
    return this.components[type]
  }

  /**
   * 注册或更新活动栏（Activitybar）模型。
   * 如果模型中的组件是一个函数，则异步加载该组件。
   * @param activitybar 要注册或更新的活动栏模型
   */
  registerActivitybar(activitybar: ActivitybarModel): void {
    // 如果组件是一个函数，则异步加载该组件
    if (typeof activitybar.component === 'function') {
      activitybar.component = loadAsyncComponent(activitybar.component)
    }

    // 默认visible为true
    if (typeof activitybar.visible === 'undefined') {
      activitybar.visible = true
    }

    // 查找活动栏在列表中的索引
    const index = this.viewsContainers.activitybars.value.findIndex(
      item => item.id === activitybar.id,
    )

    // 如果找到相同 id 的活动栏，则更新该活动栏模型
    if (index !== -1) {
      this.viewsContainers.activitybars.value[index] = activitybar
    }
    else {
      // 否则将新的活动栏模型添加到活动栏列表中
      this.viewsContainers.activitybars.value.push(activitybar)
    }
  }

  /**
   * 获取所有activitybars
   * @returns activitybars
   */
  getActivitybars(): ActivitybarModel[] {
    return this.viewsContainers.activitybars.value
  }

  /**
   * 隐藏活动栏
   * @param value 属性
   * @param attr 查询字段 默认值 title
   */
  hideActivitybar(value: string, attr = 'title') {
    // 查找具有指定属性和值的活动栏的索引
    const index = this.viewsContainers.activitybars.value.findIndex(
      (rightSidebar: any) => rightSidebar[attr] === value,
    )

    // 如果找到匹配的活动栏
    if (index !== -1) {
      // 将匹配的活动栏的 'visible' 属性设置为 false
      this.viewsContainers.activitybars.value[index].visible = false
    }
  }

  /**
   * 显示活动栏
   * @param value 属性
   * @param attr 查询字段 默认值 title
   */
  showActivitybar(value: string, attr = 'title') {
    // 查找具有指定属性和值的活动栏的索引
    const index = this.viewsContainers.activitybars.value.findIndex(
      (rightSidebar: any) => rightSidebar[attr] === value,
    )

    // 如果找到匹配的活动栏
    if (index !== -1) {
      // 将匹配的活动栏的 'visible' 属性设置为 true
      this.viewsContainers.activitybars.value[index].visible = true
    }
  }

  /**
   * 注册右侧栏
   */
  registerRightSidebar(rightSidebar: RightSidebarModel): void {
    if (typeof rightSidebar.component === 'function') {
      rightSidebar.component = loadAsyncComponent(rightSidebar.component)
    }

    // 默认visible为true
    if (typeof rightSidebar.visible === 'undefined') {
      rightSidebar.visible = true
    }

    const index = this.viewsContainers.rightSidebars.value.findIndex(
      sidebar => sidebar.id === rightSidebar.id,
    )

    if (index !== -1) {
      this.viewsContainers.rightSidebars.value[index] = rightSidebar
    }
    else {
      this.viewsContainers.rightSidebars.value.push(rightSidebar)
    }
  }

  /**
   * 获取所有rightSidebars
   * @returns rightSidebars
   */
  getRightSidebars(): RightSidebarModel[] {
    return this.viewsContainers.rightSidebars.value
  }

  /**
   * 隐藏右侧边栏
   * @param value 属性
   * @param attr 查询字段 默认值 title
   */
  hideRightSidebar(value: string, attr = 'title') {
    // 查找具有指定属性和值的右侧边栏的索引
    const index = this.viewsContainers.rightSidebars.value.findIndex(
      rightSidebar => rightSidebar[attr] === value,
    )

    // 如果找到匹配的右侧边栏
    if (index !== -1) {
      // 将匹配的右侧边栏的 'visible' 属性设置为 false
      this.viewsContainers.rightSidebars.value[index].visible = false
    }
  }

  /**
   * 显示右侧边栏
   * @param value 属性
   * @param attr 查询字段 默认值 title
   */
  showRightSidebar(value: string, attr = 'title') {
    // 查找具有指定属性和值的右侧边栏的索引
    const index = this.viewsContainers.rightSidebars.value.findIndex(
      rightSidebar => rightSidebar[attr] === value,
    )

    // 如果找到匹配的右侧边栏
    if (index !== -1) {
      // 将匹配的右侧边栏的 'visible' 属性设置为 true
      this.viewsContainers.rightSidebars.value[index].visible = true
    }
  }

  /**
   * 获取所有插件管理中的所有组件配置
   * @returns componentAttrs
   */
  getComponentConfings(): ComponentConfigModelRecords {
    return this.componentConfigs
  }

  /*
   * 通过type获取ComponentConfing
   * @returns
   */
  getComponentConfingByType(type: string): ComponentConfigModel {
    return this.componentConfigs[type]
  }

  /**
   * 计算componentSchemaGroups
   */
  computedComponentSchemaGroups() {
    const componentSchemaGroups: ComponentSchemaGroups = []

    // 遍历组件配置字典的值
    Object.values(this.componentConfigs).forEach((componentConfig) => {
      // 如果组件的默认模式的类型在隐藏组件列表中，则跳过
      if (this.hiddenComponents.includes(componentConfig.defaultSchema.type)) {
        // 跳过当前循环，继续下一个组件
        return
      }

      // 如果组件配置中有分组名
      if (componentConfig.groupName) {
        // 查找当前分组在列表中的索引

        const groupName
          = this.componentGroupNameMap[componentConfig.groupName]
          ?? componentConfig.groupName

        let groupIndex = componentSchemaGroups.findIndex(
          item => item.title === groupName,
        )

        // 如果找不到分组，表示该分组还未添加过，需要新建一个分组
        if (groupIndex === -1) {
          // 创建新的分组，并将其添加到分组列表中
          componentSchemaGroups.push({
            title: groupName,
            list: [],
          })
          // 获取新添加的分组的索引
          groupIndex = componentSchemaGroups.length - 1
        }

        // 查找当前组件在分组的列表中的索引
        let componentIndex = componentSchemaGroups[groupIndex].list.findIndex(
          item => item.type === componentConfig.defaultSchema.type,
        )

        // 如果找到相同类型的组件，则更新该组件结构数据
        if (componentIndex !== -1) {
          componentSchemaGroups[groupIndex].list[componentIndex]
            = componentConfig.defaultSchema
        }
        else {
          // 否则将新的组件结构数据添加到相应的分组中
          componentSchemaGroups[groupIndex].list.push(
            componentConfig.defaultSchema,
          )
        }
      }
    })

    // 调整分组排序
    componentSchemaGroups.sort((a: ComponentGroup, b: ComponentGroup) => {
      const indexA = this.sortedGroups.indexOf(a.title)
      const indexB = this.sortedGroups.indexOf(b.title)
      if (indexA === -1) {
        return 1 // a.title 不在 orderArray 中，排在后面
      }
      if (indexB === -1) {
        return -1 // b.title 不在 orderArray 中，排在前面
      }
      return indexA - indexB // 按照 orderArray 中的顺序排序
    })

    // 对每个分组内部的组件按照 componentConfig.sort 字段排序
    componentSchemaGroups.forEach((group) => {
      group.list.sort((a, b) => {
        const sortA = this.componentConfigs[a.type]?.sort ?? 1000
        const sortB = this.componentConfigs[b.type]?.sort ?? 1000
        return sortA - sortB
      })
    })

    this.componentSchemaGroups.value = componentSchemaGroups
  }

  /**
   * 按照分组获取componentSchemaGroups 暂时没啥用
   * @returns componentSchemaGroups
   */
  getComponentSchemaGroups() {
    return this.componentSchemaGroups
  }

  /**
   * 设置组件分组名称到映射名称的关系
   * @param groupName 组件分组名称
   * @param mapName 映射的名称
   */
  setComponentGroupNameMap(groupName: string, mapName: string) {
    this.componentGroupNameMap[groupName] = mapName
  }

  /**
   * 清空组件分组名称到映射名称的关系
   */
  clearComponentGroupNameMap() {
    this.componentGroupNameMap = {}
  }

  /**
   * 设置组件分组的排序
   * @param sortedGroups 包含组名和排序字段的对象数组
   */
  setSortedGroups(sortedGroups: string[]) {
    this.sortedGroups = sortedGroups
    this.computedComponentSchemaGroups()
  }

  /**
   * 清空组件分组的排序
   */
  clearSortedGroups() {
    this.sortedGroups = []
    this.computedComponentSchemaGroups()
  }

  /*
   * 添加需要隐藏的组件类型
   * @param {*} type
   * @returns
   */
  hideComponent(type: string) {
    this.hiddenComponents.push(type)
    this.computedComponentSchemaGroups()
  }

  /*
   * 移除需要隐藏的组件类型
   * @param {*} type
   * @returns
   */
  showComponent(type: string) {
    this.hiddenComponents = this.hiddenComponents.filter(
      item => item !== type,
    )
    this.computedComponentSchemaGroups()
  }

  /*
   * 设置需要隐藏的组件类型数组
   * @returns
   * @param types
   */
  setHideComponents(types: string[]) {
    this.hiddenComponents = types
    this.computedComponentSchemaGroups()
  }

  /**
   * 设置initialized的状态。
   *
   * @param value 要设置的布尔值。
   */
  setInitialized(value: boolean): void {
    this.initialized.value = value
  }

  /**
   * 添加公共方法
   * @param publicMethod
   */
  addPublicMethod(publicMethod: PublicMethodModel): void {
    // 兼容旧公共函数注册，后期可能移除该判断
    // methodName 变量改成 name
    // method 变量改成 handler
    const name = publicMethod.methodName ?? publicMethod.name
    const handler = publicMethod.method ?? publicMethod.handler

    this.publicMethods[name] = {
      ...publicMethod,
      name,
      handler,
    }
  }

  /**
   * 移除公共方法
   * @param methodName
   */
  removePublicMethod(methodName: string): void {
    delete this.publicMethods[methodName]
  }
}

export const pluginManager = new PluginManager()
